use sqlx::PgPool;
use crate::models;

#[derive(Clone)]
pub struct UsersDao {
    pub pool: PgPool,
}


impl UsersDao {
    pub async fn get_user_by_id(&self, user_id: i64) -> anyhow::Result<Option<models::User>> {
        let user:Option<models::User> = sqlx::query_as("SELECT * FROM users WHERE user_id = $1").bind(user_id).fetch_optional(&self.pool).await?;

        Ok(user)
    }

    pub async fn get_user_by_username(&self, username: &str) -> anyhow::Result<Option<models::User>> {
        let user:Option<models::User> = sqlx::query_as("SELECT * FROM users WHERE username = $1").bind(username).fetch_optional(&self.pool).await?;
        Ok(user)
    }

    pub async fn create_user(&self, username: &str, password_hash: &str, role: models::Role) -> anyhow::Result<()> {
        sqlx::query("INSERT INTO users (username, password_hash, role) VALUES ($1, $2, $3) RETURNING *")
            .bind(username)
            .bind(password_hash)
            .bind(role.to_str())
            .execute(&self.pool)
            .await?;
        Ok(())
    }

    pub async fn get_all_users(&self) -> anyhow::Result<Vec<models::User>> {
        let mut users:Vec<models::User> = sqlx::query_as("SELECT * FROM users").fetch_all(&self.pool).await?;
        for user in users.iter_mut() {
            user.password_hash = String::new();
        }
        Ok(users)
    }

    pub async fn update_user_password(&self, user_id: i64, password_hash: &str) -> anyhow::Result<()> {
        sqlx::query("UPDATE users SET password_hash = $1 WHERE user_id = $2")
            .bind(password_hash)
            .bind(user_id)
            .execute(&self.pool)
            .await?;
        Ok(())
    }

    pub async fn update_user_role(&self, user_id: i64, role: models::Role) -> anyhow::Result<()> {
        sqlx::query("UPDATE users SET role = $1 WHERE user_id = $2")
            .bind(role.to_str())
            .bind(user_id)
            .execute(&self.pool)
            .await?;
        Ok(())
    }

    pub async fn delete_user(&self, user_id: i64) -> anyhow::Result<()> {
        sqlx::query("DELETE FROM users WHERE user_id = $1")
            .bind(user_id)
            .execute(&self.pool)
            .await?;
        Ok(())
    }
}